//
//  NSResponderExtension.swift
//  JKTools
//
//  Created by 姜奎 on 2024/4/19.
//

import Cocoa

public
enum JKMouseDownEvents: String {
    case left
    case right
    
    var systemType: NSEvent.EventTypeMask {
        switch self {
        case .left:
                .leftMouseDown
        case .right:
                .rightMouseDown
        }
    }
    
}

extension NSResponder {
   
    private static var jk_mouseDownAssociatedKey: Int = 0
    
    @objc func mouseDownAction(with event: NSEvent) {
        guard let mouseDownClose = mouseDownClose else { return }
        mouseDownClose(event)
    }
    
    private var mouseDownClose: ((NSEvent)-> Void)? {
        get {
            return objc_getAssociatedObject(self, &Self.jk_mouseDownAssociatedKey) as? ((NSEvent)->Void)
        }
        set {
            objc_setAssociatedObject(self, &Self.jk_mouseDownAssociatedKey, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
        }
    }
    
    @objc func jk_mouseDown(with event: NSEvent) {
        jk_mouseDown(with: event)
        mouseDownAction(with: event)
    }
    
    private static var jk_rightMouseDownAssociatedKey: Int = 0
    
    @objc func rightMouseDownAction(with event: NSEvent) {
        guard let rightMouseDownClose = rightMouseDownClose else { return }
        rightMouseDownClose(event)
    }
    
    private var rightMouseDownClose: ((NSEvent)-> Void)? {
        get {
            return objc_getAssociatedObject(self, &Self.jk_rightMouseDownAssociatedKey) as? ((NSEvent)->Void)
        }
        set {
            objc_setAssociatedObject(self, &Self.jk_rightMouseDownAssociatedKey, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
        }
    }
    
    @objc func jk_rightMouseDown(with event: NSEvent) {
        jk_rightMouseDown(with: event)
        rightMouseDownAction(with: event)
    }
    private static var isSwizzled = false
    private func swizzling() {
        guard Self.isSwizzled == false else {
            return
        }
        Self.isSwizzled.toggle()
        swizzle(original: #selector(mouseDown(with:)), swizzled: #selector(jk_mouseDown(with:)))
        swizzle(original: #selector(rightMouseDown(with:)), swizzled: #selector(jk_rightMouseDown(with:)))
    }
    
    public func setMouseDown(_ event: JKMouseDownEvents,with action:((NSEvent) -> Void)?) {
        swizzling()
        switch event {
        case .left:
            mouseDownClose = action
        case .right:
            rightMouseDownClose = action
        }
//        AutoReleaseObjectsManager.removeAutoReleaseObject(self,with: event.rawValue)
//        guard let action = action else { return }
//        let monitor = NSEvent.addLocalMonitorForEvents(matching: event.systemType) { event in
//            action(event)
//            return event
//        }
//        guard let monitor = monitor else { return }
//        AutoReleaseObjectsManager.add(self, with: event.rawValue) {
//            NSEvent.removeMonitor(monitor)
//        }
    }
}

open class AutoReleaseObjectsManager {
    
   private class AutoReleaseObject: NSObject {
       let id: String
       let autoReleaseClose: (() -> Void)
       init(id: String, with close: @escaping () -> Void) {
           self.id = id
           self.autoReleaseClose = close
       }
       deinit {
           autoReleaseClose()
       }
   }
    
    private init() { }
    private let lock = NSLock()
    private static let `default` = AutoReleaseObjectsManager()
    private var eventMap:NSMapTable<NSObject, NSMutableDictionary> = NSMapTable.weakToStrongObjects()
    private func add(_ key: NSObject, with objectID: String, and close:  @escaping () -> Void) {
        lock.lock()
        defer {
            lock.unlock()
        }
        let autoReleaseObjects = eventMap.object(forKey: key) ?? NSMutableDictionary()
        autoReleaseObjects[objectID] = AutoReleaseObject(id: objectID, with: close)
        eventMap.setObject(autoReleaseObjects, forKey: key)
    }
    
    private func removeAutoReleaseObject(_ key: NSObject, with objectID: String) {
        lock.lock()
        defer {
            lock.unlock()
        }
        let autoReleaseObjects = eventMap.object(forKey: key)
        guard let autoReleaseObjects = eventMap.object(forKey: key) else {
            return
        }
        autoReleaseObjects.removeObject(forKey: objectID)
    }
    
    public class func add(_ key: NSObject, with objectID: String, and close:  @escaping () -> Void) {
        Self.default.add(key, with: objectID, and: close)
    }
    
    public  class func removeAutoReleaseObject(_ key: NSObject, with objectID: String) {
        Self.default.removeAutoReleaseObject(key, with: objectID)
    }
}

